package com.rom.ratethehell.protocol;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.graphics.BitmapFactory;
import android.util.Base64;

import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.json.gson.GsonFactory;
import com.rom.ratethehell.Global;
import com.rom.ratethehell.api.services.sneakapic.Sneakapic;
import com.rom.ratethehell.api.services.sneakapic.model.CommonComment;
import com.rom.ratethehell.api.services.sneakapic.model.CommonPersonalInfo;
import com.rom.ratethehell.api.services.sneakapic.model.CommonThumbnail;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsCommentPictureRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsLogOffRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsLoginRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsProfileRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsRandomPictureRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsRatingRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsRegisterRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsSendMessageRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsSpecificPictureRequest;
import com.rom.ratethehell.api.services.sneakapic.model.RequestsUpdatePicturesRequest;
import com.rom.ratethehell.api.services.sneakapic.model.ResponsesGeneralResponse;
import com.rom.ratethehell.api.services.sneakapic.model.ResponsesPictureResponse;
import com.rom.ratethehell.api.services.sneakapic.model.ResponsesProfileResponse;
import com.rom.ratethehell.api.services.sneakapic.model.ResponsesUpdatePicturesResponse;
import com.rom.ratethehell.entities.Comment;
import com.rom.ratethehell.entities.RatePicture;
import com.rom.ratethehell.entities.ServerResponse;

public class RequestOrganizer {
	private static RequestOrganizer requestOrganizer = new RequestOrganizer();
	public static ExecutorService executorService = Executors.newSingleThreadExecutor();
	private Sneakapic service = Global.SNEAKAPIC_SERVICE;
	private RequestOrganizer() {
		Sneakapic.Builder builder = new Sneakapic.Builder(AndroidHttp.newCompatibleTransport(),new GsonFactory(),null);
		service = builder.build();
	}
	public void login(final String email,final String pass,final ServerResponseListener<Long> runOnServerResponse) {
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					runOnServerResponse.onServerResponse(login(email,pass));
				} catch (IOException e) {
					runOnServerResponse.onServerError(e);
				}
			}
		});
		
	}

	public static RequestOrganizer getInstance() {
		return requestOrganizer;
	}
	public void getRandomPic(final ServerResponseListener<RatePicture> runOnServerResponse) {
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					runOnServerResponse.onServerResponse(getRandomPic());
				} catch (IOException e) {
					runOnServerResponse.onServerError(e);
				}
			}
		});
	}
	private RatePicture pictureResponseToPicture(ResponsesPictureResponse ret) {
		if (ret.getReturnCode()!=0) return null;
		byte[] bytes = Base64.decode(ret.getPicture().getBytes(),Base64.DEFAULT);
		RatePicture ratePic = new RatePicture(ret.getPictureId(),BitmapFactory.decodeByteArray(bytes, 0, bytes.length),ret.getRating(),ret.getNumberOfRaters());
		List<CommonComment> comments = ret.getComments();
		if (comments == null) return ratePic;
		for (CommonComment c : comments) {
			Comment comment = new Comment();
			comment.username = c.getUserId();
			comment.comment = c.getComment();
			ratePic.addComment(comment);
		}
		return ratePic;
	}
	public void getProfile(final String name,final ServerResponseListener<Profile> runOnServerResponse){
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					runOnServerResponse.onServerResponse(getProfile(name));
				} catch (Exception e) {
					runOnServerResponse.onServerError(e);
				}
			}
		});
	}
	public void sendRate(final long id,final int rate,final ServerResponseListener<ServerResponse> runOnServerResponse) {
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				RequestsRatingRequest request =  new RequestsRatingRequest();
				request.setRating((long) rate);
				request.setPictureId(id);
				try {
					ResponsesGeneralResponse ret = service.rate().rate(request).execute();
					if (runOnServerResponse!=null) runOnServerResponse.onServerResponse(new ServerResponse(ret.getReturnCode(), ret.getReturnMessage()));
				} catch (IOException e) {
					if (runOnServerResponse!=null) runOnServerResponse.onServerError(e);
				}
			}
		});
	}
	/**
	 * sends the rate without guarantees that it made it to the server, and if it doesnt you will not be informed.
	 * @param id
	 * @param progress
	 */
	public void sendRate(long id, int progress) {
		sendRate(id, progress,null);
	}

//	public void sendImage(final InputStream stream,final ServerResponseListener<Boolean> runOnServerResponse) {
//		executorService.execute(new Runnable() {
//			@Override
//			public void run() {
//				try {
//					runOnServerResponse.onServerResponse(sendImage(stream));
//				} catch (IOException e) {
//					runOnServerResponse.onServerError(e);
//				}
//			}
//		});
//	}
	public ArrayList<Thumbnail> sendImage(final InputStream stream) throws IOException {
		BufferedInputStream bstream=new BufferedInputStream(stream);
		RequestsUpdatePicturesRequest req = new RequestsUpdatePicturesRequest();
		ArrayList<String> array = new ArrayList<String>();
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		int nRead;
		byte[] data = new byte[16384];
		while ((nRead = bstream.read(data, 0, data.length)) != -1) {
		  buffer.write(data, 0, nRead);
		}
		buffer.flush();
		array.add(new String(Base64.encode(buffer.toByteArray(), Base64.DEFAULT)));
		buffer.close();
		stream.close();
		req.setPicsToAdd(array);
		req.setUserId(Global.userName);
		ResponsesUpdatePicturesResponse res = service.updatePictures().updatePictures(req).execute();
		return commonThumbnailsToThumbnails(res.getThumbnails());
	}
	public static String convertStreamToString(InputStream is, int bufferSize, String encoding) throws IOException {
	     
	    Reader reader = new BufferedReader(new InputStreamReader(is, encoding));
	    StringBuffer content = new StringBuffer();
	    char[] buffer = new char[bufferSize];
	    int n;
	     
	    while ( ( n = reader.read(buffer)) != -1 ) {
	        content.append(buffer,0,n);
	    }
	     
	    return content.toString();
	}
	
	public void sendComment(final long id, final String comment,final ServerResponseListener<ServerResponse> runOnServerResponse) {
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					RequestsCommentPictureRequest req = new RequestsCommentPictureRequest();
					CommonComment ccomment = new CommonComment();
					ccomment.setComment(comment);
					ccomment.setDate(new SimpleDateFormat("yyyy/MM/dd hh:mm:ss").format(new Date()));
					ccomment.setUserId(Global.userName);
					req.setComment(ccomment);
					req.setPictureId(id);
					ResponsesGeneralResponse ret = service.comment().comment(req).execute();
					runOnServerResponse.onServerResponse(new ServerResponse(ret.getReturnCode(),ret.getReturnMessage()));
				} catch (IOException e) {
					runOnServerResponse.onServerError(e);
				}
			}
		});
	}
	public void getSpecificPic(final long id,final ServerResponseListener<RatePicture> runOnServerResponse) {
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					runOnServerResponse.onServerResponse(getSpecificPic(id));
				} catch (Exception e) {
					runOnServerResponse.onServerError(e);
				} 
			}
		});
	}
	
	public void sendMessege(final String mssg,final String reciever,final String sender,final ServerResponseListener<ServerResponse> runOnServerResponse) {
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					RequestsSendMessageRequest req = new RequestsSendMessageRequest();
					req.setMessageText(mssg);
					req.setReceiverUserId(reciever);
					req.setSenderUserId(sender);
					ResponsesGeneralResponse ret = service.sendMessage().sendMessage(req).execute();
					runOnServerResponse.onServerResponse(new ServerResponse(ret.getReturnCode(),ret.getReturnMessage()));
				} catch (IOException e) {
					runOnServerResponse.onServerError(e);
				}
			}
		});
	}
	public RatePicture getRandomPic() throws IOException {
		RequestsRandomPictureRequest request =  new RequestsRandomPictureRequest();
		ResponsesPictureResponse ret = service.randomPic().randomPic(request).execute();
		return pictureResponseToPicture(ret);
	}
	public RatePicture getSpecificPic(long id) throws IOException {
		RequestsSpecificPictureRequest req = new RequestsSpecificPictureRequest();
		req.setPictureId(id);
		ResponsesPictureResponse ret = service.getSpecificPicture().getSpecificPicture(req).execute();
		if (isOk(ret.getReturnCode())) 
			return pictureResponseToPicture(ret);
		return null;
	}
	public Long login(String mEmail, String mPassword) throws IOException {
		RequestsLoginRequest loginMssg = new RequestsLoginRequest();
		loginMssg.setUserId(mEmail);
		loginMssg.setPassword(mPassword);
		return service.login().login(loginMssg).execute().getReturnCode();
	}
	public Profile getProfile(String userId) throws IOException {
		RequestsProfileRequest request = new RequestsProfileRequest();
		request.setRequestedUserId(userId);
		ResponsesProfileResponse ret = service.getProfile().getProfile(request).execute();
		if (!isOk(ret.getReturnCode())) return null;
		Profile p = new Profile();
		
		p.setInfo(ret.getPersonalInfo());
		if (ret.getThumbnails()==null) return p;
		p.addThumbnails(commonThumbnailsToThumbnails(ret.getThumbnails()));
		return p;
	}
	private ArrayList<Thumbnail> commonThumbnailsToThumbnails(List<CommonThumbnail> thumbnails) {
		ArrayList<Thumbnail> arrayList = new ArrayList<Thumbnail>();
		for (CommonThumbnail ct : thumbnails) {
			arrayList.add(commonThumbnailToThumbnail(ct));
		}
		return arrayList;
	}
	private Thumbnail commonThumbnailToThumbnail(CommonThumbnail tnail) {
		byte[] bytes = Base64.decode(tnail.getThumbnail().getBytes(),Base64.DEFAULT);
		return new Thumbnail(tnail.getPictureId(), BitmapFactory.decodeByteArray(bytes, 0, bytes.length));
	}
//	public Thumbnail getThumbnail() {
//		
//	}
	public Long register(String mEmail, String mPassword, String name,String mGender, String mCountry) throws IOException {
		RequestsRegisterRequest regReq = new RequestsRegisterRequest();
		CommonPersonalInfo comInfo;
		regReq.setPersonalInfo(comInfo=new CommonPersonalInfo());
		regReq.setUserId(mEmail);
		regReq.setPassword(mPassword);
		comInfo.setName(name);
		comInfo.setGender(mGender); 
		comInfo.setLocation(mCountry);
		return service.register().register(regReq).execute().getReturnCode();
	}
	private boolean isOk(Long returnCode) {
		return ServerError.OK.ordinal()==returnCode.intValue();
	}
	public ServerResponse sendComment(long id,Comment comment) throws IOException {
		RequestsCommentPictureRequest req = new RequestsCommentPictureRequest();
		CommonComment ccomment = new CommonComment();
		ccomment.setComment(comment.comment);
		ccomment.setDate(new SimpleDateFormat("yyyy/MM/dd hh:mm:ss").format(new Date()));
		ccomment.setUserId(comment.username);
		req.setComment(ccomment);
		req.setPictureId(id);
		ResponsesGeneralResponse ret = service.comment().comment(req).execute();
		return new ServerResponse(ret.getReturnCode(),ret.getReturnMessage());
	}
	public ServerResponse logoff() throws IOException {
		RequestsLogOffRequest req = new RequestsLogOffRequest();
		req.setUserId(Global.userName);
		ResponsesGeneralResponse ret = service.logOff().logOff(req).execute();
		return new ServerResponse(ret.getReturnCode(),ret.getReturnMessage());
	}

}
